package com.nanhai.buddhist.college.module.study.service.classclockrecord;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nanhai.buddhist.college.framework.common.exception.ErrorCode;
import com.nanhai.buddhist.college.framework.common.pojo.CommonResult;
import com.nanhai.buddhist.college.framework.common.pojo.PageResult;
import com.nanhai.buddhist.college.framework.common.util.collection.CollectionUtils;
import com.nanhai.buddhist.college.module.collegebase.api.college.CollegeApi;
import com.nanhai.buddhist.college.module.collegebase.api.college.dto.CollegesRespDTO;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.CollegeClassApi;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.dto.ClassesInfoDTO;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.dto.ClassesParentInfoDTO;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.dto.ClassesRespDTO;
import com.nanhai.buddhist.college.module.collegebase.api.department.DepartmentApi;
import com.nanhai.buddhist.college.module.collegebase.api.department.dto.DepartmentDTO;
import com.nanhai.buddhist.college.module.collegebase.api.room.RoomApi;
import com.nanhai.buddhist.college.module.collegebase.api.room.dto.RoomRespDTO;
import com.nanhai.buddhist.college.module.collegebase.api.student.StudentApi;
import com.nanhai.buddhist.college.module.collegebase.api.student.dto.StudentRespDTO;
import com.nanhai.buddhist.college.module.collegebase.api.teacher.TeacherApi;
import com.nanhai.buddhist.college.module.collegebase.api.teacher.dto.TeacherRespDTO;
import com.nanhai.buddhist.college.module.collegebase.enums.ErrorCodeConstants;
import com.nanhai.buddhist.college.module.study.controller.admin.attendancemanagement.vo.AttendanceManagementCreateReqVO;
import com.nanhai.buddhist.college.module.study.controller.admin.classclockrecord.vo.*;
import com.nanhai.buddhist.college.module.study.controller.student.attendance.vo.StudentClockRecordPageReqVO;
import com.nanhai.buddhist.college.module.study.controller.teacher.vo.BatchAddClockRecordReqVO;
import com.nanhai.buddhist.college.module.study.controller.teacher.vo.StudentClockListReqVO;
import com.nanhai.buddhist.college.module.study.controller.teacher.vo.SubjectStudentClockResVO;
import com.nanhai.buddhist.college.module.study.convert.classclockrecord.ClockRecordConvert;
import com.nanhai.buddhist.college.module.study.dal.dataobject.attendancemanagement.AttendanceManagementDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.classclockrecord.ClockRecordDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.qrcodeconfig.QrCodeConfigDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.studyplan.StudyPlanDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.studysubject.StudySubjectDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.studytime.StudyTimeDO;
import com.nanhai.buddhist.college.module.study.dal.dataobject.timetable.ClassTimetableDO;
import com.nanhai.buddhist.college.module.study.dal.mysql.classclockrecord.ClockRecordMapper;
import com.nanhai.buddhist.college.module.study.dal.mysql.qrcodeconfig.QrCodeConfigMapper;
import com.nanhai.buddhist.college.module.study.dal.mysql.studyplan.StudyPlanMapper;
import com.nanhai.buddhist.college.module.study.dal.mysql.studysubject.StudySubjectMapper;
import com.nanhai.buddhist.college.module.study.dal.mysql.studytime.StudyTimeMapper;
import com.nanhai.buddhist.college.module.study.enums.ClockRoleTypeEnum;
import com.nanhai.buddhist.college.module.study.enums.ClockStatusEnum;
import com.nanhai.buddhist.college.module.study.enums.ClockUpDownStatusEnum;
import com.nanhai.buddhist.college.module.study.service.studyplan.StudyPlanTeacherService;
import com.nanhai.buddhist.college.module.study.util.DateConvertUtil;
import jodd.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.nanhai.buddhist.college.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.CLASS_TIMETABLE_NOT_EXISTS;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.CLOCK_RECORD_NOT_EXISTS;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.CLOCK_TIME_NOT_EXISTS;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.CLOCK_TYPE_NOT_EXISTS;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.QRCODE_DISABLED;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.QR_CODE_CONFIG_NOT_EXISTS;
import static com.nanhai.buddhist.college.module.study.enums.ErrorCodeConstants.STUDENT_CLASS_NOT_EXISTS;

/**
 * 打卡记录 Service 实现类
 *
 * @author AKai
 */
@Service
@Validated
public class ClockRecordServiceImpl implements ClockRecordService {

    @Resource
    private ClockRecordMapper clockRecordMapper;


    @Resource
    private StudentApi studentApi;

    @Resource
    private TeacherApi teacherApi;


    @Resource
    private CollegeClassApi collegeClassApi;


    @Resource
    private StudyTimeMapper studyTimeMapper;

    @Resource
    private StudyPlanTeacherService studyPlanTeacherService;

    @Resource
    private StudySubjectMapper studySubjectMapper;

    @Resource
    private RoomApi roomApi;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private QrCodeConfigMapper qrCodeConfigMapper;

    @Resource
    private StudyPlanMapper studyPlanMapper;


    @Override
    public String createClockRecord(ClockRecordCreateReqVO createReqVO) {
        // 插入
        ClockRecordDO clockRecord = ClockRecordConvert.INSTANCE.convert(createReqVO);


        // 设置 上下课 和 基准时间 打卡状态
        setTimeAndUpDown(createReqVO, clockRecord);

        // 设置学院、系部、专业id
        setCollegeId(createReqVO, clockRecord);
        // 设置联系电话
        setUserPhone(createReqVO, clockRecord);


        // 查询今日有相同的打卡时 作为更新操作
        Date date = new Date();
        ClockRecordDO clockRecordDO = clockRecordMapper.selectOne(new LambdaQueryWrapper<ClockRecordDO>()
                .eq(ClockRecordDO::getClockUserId, clockRecord.getClockUserId())
                .eq(ClockRecordDO::getClockRole, clockRecord.getClockRole())
                .eq(ClockRecordDO::getUpDown, clockRecord.getUpDown())
                .eq(ClockRecordDO::getSubjectId, clockRecord.getSubjectId())
                .between(ClockRecordDO::getClockTime, DateConvertUtil.getBeginOfDay(date), DateConvertUtil.getEndOfDay(date))
        );

        // 有过上课打卡记录  直接返回
        if (ObjectUtil.isNotNull(clockRecordDO) && ClockUpDownStatusEnum.UP.getStatus().equals(clockRecord.getUpDown())) {
            return clockRecordDO.getId();
        }

        if (ObjectUtil.isNotNull(clockRecordDO)) {
            clockRecord.setId(clockRecordDO.getId());
            clockRecord.setClockTime(date);
            clockRecordMapper.updateById(clockRecord);

        } else {
            clockRecord.setClockTime(ObjectUtil.isNull(clockRecord.getClockTime()) ? date : clockRecord.getClockTime());
            clockRecordMapper.insert(clockRecord);
        }

        // 返回
        return clockRecord.getId();
    }

    private void setTimeAndUpDown(ClockRecordCreateReqVO createReqVO, ClockRecordDO clockRecord) {
        if (ObjectUtil.isNull(createReqVO.getUpDown())) {
            StudyTimeDO studyTimeDO = studyTimeMapper.selectById(createReqVO.getStudyTimeId());
            if (ObjectUtil.isNotNull(studyTimeDO)) {
                Date date = new Date();
                long time = date.getTime();
                Date endTime = DateConvertUtil.setTimeHMS(studyTimeDO.getEndTime(), date);
                Date beginTime = DateConvertUtil.setTimeHMS(studyTimeDO.getBeginTime(), date);
                QrCodeConfigDO qrCodeConfigDO = qrCodeConfigMapper.selectOne(new LambdaQueryWrapper<QrCodeConfigDO>().last("limit 1"));
                if (ObjectUtil.isNull(qrCodeConfigDO)) {
                    throw exception(QR_CODE_CONFIG_NOT_EXISTS);
                }


                // 下课提前时间  和  结束时间
                long quittingAdvanceTime = qrCodeConfigDO.getQuittingTimeAdvance() * 60 * 1000;
                long quittingStopTime = qrCodeConfigDO.getQuittingTimeStop() * 60 * 1000;

                // 上课 提前时间和 结束时间
                long studyAdvanceTime = qrCodeConfigDO.getStudyTimeAdvance() * 60 * 1000;
                long studyStopTime = qrCodeConfigDO.getStudyTimeAdvance() * 60 * 1000;

                if (time > (endTime.getTime() - quittingAdvanceTime) && time < (endTime.getTime() + quittingStopTime)) {
                    clockRecord.setUpDown(ClockUpDownStatusEnum.DOWN.getStatus());
                    clockRecord.setStandardTime(studyTimeDO.getEndTime());

                    if (date.getTime() < DateConvertUtil.setTimeHMS(studyTimeDO.getEndTime(), date).getTime()) {
                        clockRecord.setClockStatus(ClockStatusEnum.ABNORMAL.getStatus());
                    } else {
                        clockRecord.setClockStatus(ClockStatusEnum.NORMAL.getStatus());
                    }
                } else if (time > (beginTime.getTime() - studyAdvanceTime) && time < (beginTime.getTime() + studyStopTime)) {
                    clockRecord.setUpDown(ClockUpDownStatusEnum.UP.getStatus());
                    clockRecord.setStandardTime(studyTimeDO.getBeginTime());

                    if (date.getTime() > DateConvertUtil.setTimeHMS(studyTimeDO.getBeginTime(), date).getTime()) {
                        clockRecord.setClockStatus(ClockStatusEnum.ABNORMAL.getStatus());
                    } else {
                        clockRecord.setClockStatus(ClockStatusEnum.NORMAL.getStatus());
                    }

                } else {
                    throw exception(CLOCK_TIME_NOT_EXISTS);
                }
            }
        }
    }

    private void setUserPhone(ClockRecordCreateReqVO createReqVO, ClockRecordDO clockRecordDO) {
        if (ClockRoleTypeEnum.STUDENT.getRole().equals(createReqVO.getClockRole())) {
            StudentRespDTO studentRespDTO = studentApi.getStudentRespDTOById(createReqVO.getClockUserId()).getCheckedData();
            clockRecordDO.setClockUserName(studentRespDTO.getStudentName());
            clockRecordDO.setUserPhone(studentRespDTO.getPhone());
        } else {
            TeacherRespDTO teacherRespDTO = teacherApi.getTeacherById(createReqVO.getClockUserId()).getCheckedData();
            clockRecordDO.setUserPhone(teacherRespDTO.getTeacherTelephone());
            clockRecordDO.setClockUserName(teacherRespDTO.getTeacherName());
        }
    }


    private void setCollegeId(ClockRecordCreateReqVO createReqVO, ClockRecordDO clockRecord) {
        if (StringUtils.isBlank(clockRecord.getClassesId())) {
            return;
        }
        ClassesParentInfoDTO checkedData = collegeClassApi.getClassesParentInfoDTOByClassesId(createReqVO.getClassesId()).getCheckedData();
        clockRecord.setCollegeId(checkedData.getCollegeId());
        clockRecord.setProfessionId(checkedData.getProfessionsId());
        clockRecord.setDepartmentsId(checkedData.getDepartmentsId());
    }

    @Override
    public void updateClockRecord(ClockRecordUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateClockRecordExists(updateReqVO.getId());
        // 更新
        ClockRecordDO updateObj = ClockRecordConvert.INSTANCE.convert(updateReqVO);
        clockRecordMapper.updateById(updateObj);
    }

    @Override
    public void deleteClockRecord(String id) {
        // 校验存在
        this.validateClockRecordExists(id);
        // 删除
        clockRecordMapper.deleteById(id);
    }

    private void validateClockRecordExists(String id) {
        if (clockRecordMapper.selectById(id) == null) {
            throw exception(CLOCK_RECORD_NOT_EXISTS);
        }
    }

    @Override
    public ClockRecordDO getClockRecord(String id) {
        List<ClockRecordDO> list = new ArrayList<>(2);
        ClockRecordDO clockRecordDO = clockRecordMapper.selectById(id);
        list.add(clockRecordDO);
        return toClockRecordVo(list).get(0);
    }

    @Override
    public List<ClockRecordDO> getClockRecordList(Collection<String> ids) {
        return CollectionUtils.isEmpty(ids) ? Collections.emptyList() : clockRecordMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ClockRecordDO> getClockRecordPage(ClockRecordPageReqVO pageReqVO) {
        // 管理端 查询日期起始时间
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(pageReqVO.getClockEndTime())) {
            pageReqVO.setClockEndTimeDate(DateConvertUtil.stringToDateEnd(pageReqVO.getClockEndTime()));
        }
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(pageReqVO.getClockStartTime())) {
            pageReqVO.setClockStartTimeDate(DateConvertUtil.stringToDateStart(pageReqVO.getClockStartTime()));
        }

        // 移动端  周期数查询  设置查询起始时间
        setWeekDateQuery(pageReqVO);

        // 管理端请求时处理入参 通过教师id查询班级 再通过班级查学生打卡记录
        adminSelectSetReq(pageReqVO);

        PageResult<ClockRecordDO> page = clockRecordMapper.selectPage(pageReqVO);
        page.setList(toClockRecordVo(page.getList()));
        return page;
    }

    private void setWeekDateQuery(ClockRecordPageReqVO pageReqVO) {
        // 教学计划主键 、 周数 、 学期标识   不为空 做周期查询
        if (ObjectUtil.isNotNull(pageReqVO.getStudyPlanId())
                && ObjectUtil.isNotNull(pageReqVO.getWeekNo())
                && ObjectUtil.isNotNull(pageReqVO.getSemesterIndex())) {
            StudyPlanDO studyPlanDO = studyPlanMapper.selectById(pageReqVO.getStudyPlanId());
            // 手动计算日期分页
            if (pageReqVO.getSemesterIndex() == 1) {
                // 第一学期
                Date startDate = DateConvertUtil.weekStartDate(studyPlanDO.getOneStartTime(), (pageReqVO.getWeekNo() - 1) * studyPlanDO.getWeekConfig());
                pageReqVO.setWeekStartTimeDate(startDate);
                Date endDate = DateConvertUtil.weekEndDate(studyPlanDO.getOneEndTime(), pageReqVO.getWeekNo() * studyPlanDO.getWeekConfig());
                pageReqVO.setWeekEndTimeDate(endDate);
            } else {
                // 第二学期
                Date startDate = DateConvertUtil.weekStartDate(studyPlanDO.getTowStartTime(), (pageReqVO.getWeekNo() - 1) * studyPlanDO.getWeekConfig());
                pageReqVO.setWeekStartTimeDate(startDate);
                Date endDate = DateConvertUtil.weekEndDate(studyPlanDO.getTowEndTime(), pageReqVO.getWeekNo() * studyPlanDO.getWeekConfig());
                pageReqVO.setWeekEndTimeDate(endDate);
            }
        }
    }


    private void adminSelectSetReq(ClockRecordPageReqVO pageReqVO) {
        if (StringUtil.isNotBlank(pageReqVO.getTeacherId())) {
            List<ClassesInfoDTO> classesInfoDTOS = collegeClassApi.getClassesInfoDTOListByTeacher(pageReqVO.getTeacherId()).getData();
            if (CollectionUtil.isNotEmpty(classesInfoDTOS)) {
                pageReqVO.setClassesIds(classesInfoDTOS.stream().map(ClassesInfoDTO::getId).collect(Collectors.toList()));
            }
            pageReqVO.setRole(ClockRoleTypeEnum.STUDENT.getRole());
        }
    }

    @Override
    public List<ClockRecordDO> getClockRecordList(ClockRecordExportReqVO exportReqVO) {
        return clockRecordMapper.selectList(exportReqVO);
    }

    @Override
    public void batchAddClockRecord(BatchAddClockRecordReqVO reqVO) {
        QrCodeConfigDO qrCodeConfigDO = qrCodeConfigMapper.selectOne(new LambdaQueryWrapper<QrCodeConfigDO>().last("limit 1"));
        if (ObjectUtil.isNull(qrCodeConfigDO)) {
            throw exception(QR_CODE_CONFIG_NOT_EXISTS);
        }
     /*   if (StringUtil.isNotBlank(qrCodeConfigDO.getClockType()) &&  !qrCodeConfigDO.getClockType().contains(reqVO.getClockType())){
            throw exception(CLOCK_TYPE_NOT_EXISTS); todo
        }*/


        List<String> list = reqVO.getClockUserIds();
        list.forEach(item -> {
            ClockRecordCreateReqVO createReqVO = new ClockRecordCreateReqVO();
            BeanUtils.copyProperties(reqVO, createReqVO);
            createReqVO.setClockUserId(item);
            this.createClockRecord(createReqVO);
        });

    }


    private List<ClockRecordDO> toClockRecordVo(List<ClockRecordDO> list) {
        if (CollectionUtil.isEmpty(list)) {
            return list;
        }
        List<String> classesIds = CollectionUtils.convertList(list, ClockRecordDO::getClassesId);
        Map<String, ClassesParentInfoDTO> stringClassesParentInfoDTOMap = Collections.EMPTY_MAP;
        if (CollectionUtil.isNotEmpty(classesIds)) {
            List<ClassesRespDTO> classesList = collegeClassApi.getClassesList(classesIds).getCheckedData();

            final CommonResult<List<ClassesParentInfoDTO>> classesParentInfoDTOByClassesIds = collegeClassApi.getClassesParentInfoDTOByClassesIds(classesIds);

            stringClassesParentInfoDTOMap = CollectionUtils.convertMap(classesParentInfoDTOByClassesIds.getData(), ClassesParentInfoDTO::getClassesId);
        }
        List<String> subjectIds = CollectionUtils.convertList(list, ClockRecordDO::getSubjectId);
        final List<StudySubjectDO> studySubjectDOS = studySubjectMapper.selectBatchIds(subjectIds);

        List<String> roomIds = CollectionUtils.convertList(list, ClockRecordDO::getRoomId);
        List<RoomRespDTO> roomRespDTOS = roomApi.getClassroomInfoList(roomIds).getCheckedData();

        Map<String, ClassesParentInfoDTO> finalStringClassesParentInfoDTOMap = stringClassesParentInfoDTOMap;
        list.forEach(item -> {
            getClockUserName(item);
            item.setDepartmentName(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getDepartmentsName).orElse(""));
            item.setCollegeId(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getCollegeId).orElse(""));
            item.setCollegeName(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getCollegeName).orElse(""));
            item.setDepartmentsId(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getDepartmentsId).orElse(""));
            item.setProfessionId(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getProfessionsId).orElse(""));
            item.setClassName(Optional.ofNullable(finalStringClassesParentInfoDTOMap).map(s -> s.get(item.getClassesId())).map(ClassesParentInfoDTO::getClassesName).orElse(""));


            if (CollectionUtil.isNotEmpty(roomRespDTOS)) {
                List<RoomRespDTO> collect = roomRespDTOS.stream().filter(s -> s.getId().equals(item.getRoomId())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(collect)) {
                    RoomRespDTO roomRespDTO = collect.get(0);
                    item.setRoomName(roomRespDTO.getClassroomName());
                    item.setAddress(roomRespDTO.getAddress());
                }
            }

            if (CollectionUtil.isNotEmpty(studySubjectDOS)) {
                List<StudySubjectDO> collect = studySubjectDOS.stream().filter(s -> s.getId().equals(item.getSubjectId())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(collect)) {
                    final StudySubjectDO studySubjectDO = collect.get(0);
                    item.setSubjectName(studySubjectDO.getName());
                }
            }


        });

        return list;
    }

    /**
     * 根据角色类型获取教师或者学生昵称
     *
     * @param item
     */
    private void getClockUserName(ClockRecordDO item) {
        if (ClockRoleTypeEnum.STUDENT.getRole().equals(item.getClockRole())) {
            StudentRespDTO studentRespDTO = studentApi.getStudentRespDTOById(item.getClockUserId()).getData();
            if (ObjectUtil.isNotEmpty(studentRespDTO)) {
                item.setClockUserName(studentRespDTO.getStudentName());
            }
        } else {
            TeacherRespDTO teacherRespDTO = teacherApi.getTeacherById(item.getClockUserId()).getCheckedData();
            if (ObjectUtil.isNotEmpty(teacherRespDTO)) {
                item.setClockUserName(teacherRespDTO.getTeacherName());
            }
        }
    }

    @Override
    public PageResult<ClockRecordDO> getStudentClockRecordPage(StudentClockRecordPageReqVO pageVO) {
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(pageVO.getClockEndTime())) {
            pageVO.setClockEndTimeDate(DateConvertUtil.stringToDateEnd(pageVO.getClockEndTime()));
        }
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(pageVO.getClockStartTime())) {
            pageVO.setClockStartTimeDate(DateConvertUtil.stringToDateStart(pageVO.getClockStartTime()));
        }
        setWeekFindQuery(pageVO);

        PageResult<ClockRecordDO> page = clockRecordMapper.selectPage1(pageVO);
        page.setList(toClockRecordVo(page.getList()));
        return page;
    }

    private void setWeekFindQuery(StudentClockRecordPageReqVO pageVO) {
        // 教学计划主键 、 周数 、 学期标识   不为空 做周期查询
        if (ObjectUtil.isNotNull(pageVO.getStudyPlanId())
                && ObjectUtil.isNotNull(pageVO.getWeekNo())
                && ObjectUtil.isNotNull(pageVO.getSemesterIndex())) {
            StudyPlanDO studyPlanDO = studyPlanMapper.selectById(pageVO.getStudyPlanId());
            // 手动计算日期分页
            if (pageVO.getSemesterIndex() == 1) {
                // 第一学期
                Date startDate = DateConvertUtil.weekStartDate(studyPlanDO.getOneStartTime(), (pageVO.getWeekNo() - 1) * studyPlanDO.getWeekConfig());
                pageVO.setWeekStartTimeDate(startDate);
                Date endDate = DateConvertUtil.weekEndDate(studyPlanDO.getOneEndTime(), pageVO.getWeekNo() * studyPlanDO.getWeekConfig());
                pageVO.setWeekEndTimeDate(endDate);
            } else {
                // 第二学期
                Date startDate = DateConvertUtil.weekStartDate(studyPlanDO.getTowStartTime(), (pageVO.getWeekNo() - 1) * studyPlanDO.getWeekConfig());
                pageVO.setWeekStartTimeDate(startDate);
                Date endDate = DateConvertUtil.weekEndDate(studyPlanDO.getTowEndTime(), pageVO.getWeekNo() * studyPlanDO.getWeekConfig());
                pageVO.setWeekEndTimeDate(endDate);
            }
        }
    }

    @Override
    public List<ClockRecordDO> getTodayClock(ClockRecordTodayReqVO reqVO) {
        LambdaQueryWrapper<ClockRecordDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClockRecordDO::getClockUserId, reqVO.getClockUserId())
                .eq(ClockRecordDO::getClockRole, reqVO.getClockRole())
                .between(ClockRecordDO::getClockTime, DateConvertUtil.getBeginOfDay(reqVO.getFindTime()), DateConvertUtil.getEndOfDay(reqVO.getFindTime()))
                .eq(ObjectUtil.isNotEmpty(reqVO.getClockStatus()), ClockRecordDO::getClockStatus, reqVO.getClockStatus())
                .eq(ClockRecordDO::getStudyTimeId, reqVO.getStudyTimeId())
                .eq(ObjectUtil.isNotEmpty(reqVO.getSubjectId()), ClockRecordDO::getSubjectId, reqVO.getSubjectId());
        List<ClockRecordDO> resList = clockRecordMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(resList)) {
            return resList;
        }
        // 返回参数设计教师和班级昵称
        setClassesAndTeacherName(resList);
        return resList;
    }

    @Override
    public List<ClockRecordDO> getTodayClockBySubjectId(ClockRecordUserReqVO reqVO) {
        LambdaQueryWrapper<ClockRecordDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClockRecordDO::getClockUserId, reqVO.getClockUserId())
                .eq(ClockRecordDO::getClockRole, reqVO.getClockRole())
                .between(ClockRecordDO::getClockTime, DateConvertUtil.getBeginOfDay(reqVO.getFindTime()), DateConvertUtil.getEndOfDay(reqVO.getFindTime()))
                .eq(ObjectUtil.isNotEmpty(reqVO.getClockStatus()), ClockRecordDO::getClockStatus, reqVO.getClockStatus())
                .eq(ClockRecordDO::getStudyTimeId, reqVO.getStudyTimeId())
                .eq(ClockRecordDO::getSubjectId, reqVO.getSubjectId());
        List<ClockRecordDO> resList = clockRecordMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(resList)) {
            return resList;
        }
        // 返回参数设计教师和班级昵称
        setClassesAndTeacherName(resList);
        return resList;
    }

    @Override
    public String scanCodeClock(ScanCodeClockReqVO codeClockReqVO) {
        String qrCoedStr = codeClockReqVO.getQrCoedStr();
        // 检验打卡信息
        ClassTimetableDO data = scanCodeClockCheck(codeClockReqVO, qrCoedStr);

        // 获取上下课标识
        String upDown = qrCoedStr.substring(qrCoedStr.length() - 1);
        ClockRecordCreateReqVO createReqVO = new ClockRecordCreateReqVO();

        // 封装入参
        privateParam(codeClockReqVO, data, upDown, createReqVO);

        // 调用创建接口
        return this.createClockRecord(createReqVO);
    }

    @NotNull
    private ClassTimetableDO scanCodeClockCheck(ScanCodeClockReqVO codeClockReqVO, String qrCoedStr) {
        // 校验二维码是否过期
        if (!redisTemplate.hasKey(qrCoedStr)) {
            throw exception(QRCODE_DISABLED);
        }
        // 获取二维码配置
        QrCodeConfigDO qrCodeConfigDO = qrCodeConfigMapper.selectOne(new LambdaQueryWrapper<QrCodeConfigDO>().last("limit 1"));
        if (ObjectUtil.isNull(qrCodeConfigDO)) {
            throw exception(QR_CODE_CONFIG_NOT_EXISTS);
        }

      /*  if (StringUtil.isNotBlank(qrCodeConfigDO.getClockType()) &&  !qrCodeConfigDO.getClockType().contains(codeClockReqVO.getClockType())){
            throw exception(CLOCK_TYPE_NOT_EXISTS);
        }*/
        // 获取缓存打卡信息
        ClassTimetableDO data = (ClassTimetableDO) redisTemplate.opsForValue().get(qrCoedStr);
        if (ObjectUtil.isNull(data)) {
            throw exception(CLASS_TIMETABLE_NOT_EXISTS);
        }

        // 获取学生信息
        StudentRespDTO studentDTO = studentApi.getStudentRespDTOById(codeClockReqVO.getClockUserId()).getData();
        if (ObjectUtil.isNull(studentDTO)) {
            throw exception(ErrorCodeConstants.STUDENT_ROLL_NOT_EXISTS);
        }
        // 校验是否在相同班级
        if (!studentDTO.getClassesId().equals(data.getClassesId())) {
            throw exception(STUDENT_CLASS_NOT_EXISTS);
        }
        return data;
    }

    /**
     * 封装入参
     *
     * @param codeClockReqVO
     * @param data
     * @param upDown
     * @param createReqVO
     */
    private void privateParam(ScanCodeClockReqVO codeClockReqVO, ClassTimetableDO data, String upDown, ClockRecordCreateReqVO createReqVO) {
        Date date = new Date();
        createReqVO.setClockUserId(codeClockReqVO.getClockUserId());
        createReqVO.setClockType(codeClockReqVO.getClockType());
        createReqVO.setClockRole(codeClockReqVO.getClockRole());
        createReqVO.setClockTime(date);

        createReqVO.setRoomId(data.getRoomId());
        createReqVO.setStudyTimeId(data.getStudyTimeId());
        createReqVO.setSubjectId(data.getSubjectId());
        createReqVO.setClassesId(data.getClassesId());
        createReqVO.setWeekId(data.getWeekId());
        StudyTimeDO studyTimeDO = studyTimeMapper.selectById(data.getStudyTimeId());

        if (ClockUpDownStatusEnum.DOWN.getStatus() == Integer.parseInt(upDown)) {
            createReqVO.setStandardTime(studyTimeDO.getEndTime());
            createReqVO.setUpDown(ClockUpDownStatusEnum.DOWN.getStatus());
            if (date.getTime() < DateConvertUtil.setTimeHMS(studyTimeDO.getEndTime(), date).getTime()) {
                createReqVO.setClockStatus(ClockStatusEnum.ABNORMAL.getStatus());
            } else {
                createReqVO.setClockStatus(ClockStatusEnum.NORMAL.getStatus());
            }
        } else {
            createReqVO.setStandardTime(studyTimeDO.getBeginTime());
            createReqVO.setUpDown(ClockUpDownStatusEnum.UP.getStatus());
            if (date.getTime() > DateConvertUtil.setTimeHMS(studyTimeDO.getBeginTime(), date).getTime()) {
                createReqVO.setClockStatus(ClockStatusEnum.ABNORMAL.getStatus());
            } else {
                createReqVO.setClockStatus(ClockStatusEnum.NORMAL.getStatus());
            }
        }


    }


    /**
     * 设置 班级和教师昵称
     *
     * @param resList
     */
    private void setClassesAndTeacherName(List<ClockRecordDO> resList) {
        // 统计将数据查询 内存处理
        List<String> classesIds = resList.stream().map(ClockRecordDO::getClassesId).distinct().collect(Collectors.toList());
        List<ClassesRespDTO> classesList = collegeClassApi.getClassesList(classesIds).getCheckedData();


        resList.forEach(item -> {
            // 获取班级昵称
            if (CollectionUtil.isNotEmpty(classesList)) {
                List<ClassesRespDTO> classesRespDTOs = classesList.stream().filter(s -> s.getId().equals(item.getClassesId())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(classesRespDTOs)) {
                    ClassesRespDTO classesRespDTO = classesRespDTOs.get(0);
                    item.setClassName(classesRespDTO.getClassesName());
                }
            }

            if (ObjectUtil.isNotEmpty(item.getSubjectId())) {
                // 设置课程昵称
                StudySubjectDO studySubjectDO = studySubjectMapper.selectById(item.getSubjectId());
                item.setSubjectName(ObjectUtil.isNotEmpty(studySubjectDO) ? studySubjectDO.getName() : "");
                // 设置教师昵称
                String teacherId = studyPlanTeacherService.selectTeacherIdBySubjectId(item.getSubjectId());
                TeacherRespDTO teacherRespDTO = teacherApi.getTeacherById(teacherId).getCheckedData();
                item.setTeacherName(ObjectUtil.isNotEmpty(teacherRespDTO) ? teacherRespDTO.getTeacherName() : "");

            }
        });
    }

    @Override
    public List<SubjectStudentClockResVO> getStudentClockList(StudentClockListReqVO reqVO) {
        List<SubjectStudentClockResVO> resVOList = new ArrayList<>();
        List<StudentRespDTO> data = studentApi.getStudentListByClassesId(reqVO.getClassesId()).getData();
        if (CollectionUtils.isEmpty(data)) {
            return resVOList;
        }
        List<String> studentIds = data.stream().map(StudentRespDTO::getId).collect(Collectors.toList());

        // 查询当前课程学生打卡情况
        final List<ClockRecordDO> clockRecordDOS = clockRecordMapper.selectList(new LambdaQueryWrapper<ClockRecordDO>()
                .eq(ClockRecordDO::getSubjectId, reqVO.getSubjectId())
                .eq(ClockRecordDO::getStudyTimeId, reqVO.getStudyTimeId())
                .eq(ClockRecordDO::getClassesId, reqVO.getClassesId())
                .eq(ClockRecordDO::getWeekId, reqVO.getWeekId())
                .eq(ClockRecordDO::getClockRole, ClockRoleTypeEnum.STUDENT.getRole())
                .eq(ClockRecordDO::getUpDown, reqVO.getUpDown())
                .in(ClockRecordDO::getClockUserId, studentIds)
                .between(ClockRecordDO::getClockTime, DateConvertUtil.getBeginOfDay(reqVO.getFindTime()), DateConvertUtil.getEndOfDay(reqVO.getFindTime()))
        );

        // 判断是否打卡
        data.forEach(item -> {
            SubjectStudentClockResVO subjectStudentClockResVO = new SubjectStudentClockResVO();
            BeanUtils.copyProperties(item, subjectStudentClockResVO);
            subjectStudentClockResVO.setIsClock(false);
            if (CollectionUtils.isNotEmpty(clockRecordDOS)) {
                long count = clockRecordDOS.stream().filter(s -> s.getClockUserId().equals(item.getId())).count();
                if (count > 0) {
                    subjectStudentClockResVO.setIsClock(true);
                }
            }
            resVOList.add(subjectStudentClockResVO);

        });

        return resVOList;
    }
}
